"""Smart Import service: AI provider integration and persistence.

This module provides:
- SmartImportAIProvider: optional HTTP AI extraction provider (default base url from settings)
- Fallback parser: deterministic CSV-like parser
- SmartImportPersistence: lightweight persistence using raw SQL (CREATE TABLE IF NOT EXISTS)
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

import httpx
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.config import settings


SUPPORTED_UNITS = {"kg", "g", "t", "lb"}


class AIProviderError(Exception):
    pass


@dataclass
class SmartImportAIProvider:
    base_url: str
    timeout: float = 10.0

    @classmethod
    def from_settings(cls) -> SmartImportAIProvider:
        return cls(base_url=settings.SMART_IMPORT_AI_URL, timeout=settings.SMART_IMPORT_AI_TIMEOUT)

    async def extract(self, text: str) -> list[dict[str, Any]]:
        """Call external AI service to extract items.

        Expected response JSON: { items: [{name, quantity, unit}], degraded?: bool }
        """
        url = self.base_url.rstrip("/") + "/extract"
        try:
            async with httpx.AsyncClient(timeout=self.timeout) as client:
                resp = await client.post(url, json={"text": text})
                if resp.status_code >= 400:
                    raise AIProviderError(f"AI service HTTP {resp.status_code}: {resp.text}")
                data = resp.json()
        except Exception as e:
            raise AIProviderError(f"AI provider error: {e!s}")

        items = []
        for it in data.get("items", []):
            name = str(it.get("name", "")).strip()
            try:
                qty = float(it.get("quantity", 0))
            except Exception:
                continue
            unit = str(it.get("unit", "kg")).lower()
            if not name or qty < 0 or unit not in SUPPORTED_UNITS:
                continue
            items.append({"name": name, "quantity": qty, "unit": unit})
        return items


def parse_text(text: str) -> list[dict[str, Any]]:
    """Deterministic fallback parser: each line 'name,quantity,unit'."""
    lines = [ln.strip() for ln in text.splitlines()]
    lines = [ln for ln in lines if ln and not ln.startswith("#")]  # ignore comments
    items: list[dict[str, Any]] = []
    for ln in lines:
        parts = [p.strip() for p in ln.split(",")]
        if len(parts) < 3:
            continue
        name, qty_str, unit = parts[0], parts[1], parts[2]
        try:
            qty = float(qty_str)
        except Exception:
            continue
        unit = unit.lower()
        if not name or qty < 0 or unit not in SUPPORTED_UNITS:
            continue
        items.append({"name": name, "quantity": qty, "unit": unit})
    return items


def validate_items(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
    """Strict validation and normalization for items."""
    normalized: list[dict[str, Any]] = []
    for it in items:
        name = str(it.get("name", "")).strip()
        try:
            qty = float(it.get("quantity", 0))
        except Exception:
            qty = -1
        unit = str(it.get("unit", "kg")).lower()
        target = str(it.get("target_unit", unit)).lower()

        if not name or len(name) > 255:
            raise ValueError("Invalid name")
        if qty < 0:
            raise ValueError("Quantity must be non-negative")
        if unit not in SUPPORTED_UNITS or target not in SUPPORTED_UNITS:
            raise ValueError("Unsupported unit")
        normalized.append({"name": name, "quantity": qty, "unit": unit, "target_unit": target})
    return normalized


class SmartImportPersistence:
    """Lightweight persistence using raw SQL to avoid migration overhead."""

    @staticmethod
    async def init_tables(db: AsyncSession) -> None:
        await db.execute(
            text(
                """
                CREATE TABLE IF NOT EXISTS smart_import_batches (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    project_id INTEGER NOT NULL,
                    warehouse TEXT,
                    source_text TEXT,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
                """
            )
        )
        await db.execute(
            text(
                """
                CREATE TABLE IF NOT EXISTS smart_import_items (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    batch_id INTEGER NOT NULL,
                    name TEXT NOT NULL,
                    quantity REAL NOT NULL,
                    unit TEXT NOT NULL,
                    target_unit TEXT NOT NULL,
                    final_quantity REAL NOT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
                """
            )
        )

    @staticmethod
    async def commit(
        db: AsyncSession,
        project_id: int,
        items: list[dict[str, Any]],
        source_text: str | None = None,
        warehouse: str | None = None,
    ) -> int:
        await SmartImportPersistence.init_tables(db)
        # Create batch
        result = await db.execute(
            text(
                """
                INSERT INTO smart_import_batches (project_id, warehouse, source_text)
                VALUES (:project_id, :warehouse, :source_text)
                RETURNING id
                """
            ),
            {"project_id": project_id, "warehouse": warehouse, "source_text": source_text},
        )
        row = result.fetchone()
        batch_id = int(row[0]) if row else 0

        # Insert items
        for it in items:
            await db.execute(
                text(
                    """
                    INSERT INTO smart_import_items (batch_id, name, quantity, unit, target_unit, final_quantity)
                    VALUES (:batch_id, :name, :quantity, :unit, :target_unit, :final_quantity)
                    """
                ),
                {
                    "batch_id": batch_id,
                    "name": it["name"],
                    "quantity": it["quantity"],
                    "unit": it["unit"],
                    "target_unit": it["target_unit"],
                    "final_quantity": it["final_quantity"],
                },
            )
        await db.commit()
        return len(items)

# End of file
